package main

import "fmt"

// https://refactoringguru.cn/design-patterns/abstract-factory

type GUIFactory interface {
	NewButton() Button
	NewDialog() Dialog
}

type WinFactory struct{}

func (*WinFactory) NewButton() Button { return new(WinButton) }
func (*WinFactory) NewDialog() Dialog { return new(WinDialog) }

type MacFactory struct{}

func (*MacFactory) NewButton() Button { return new(MacButton) }
func (*MacFactory) NewDialog() Dialog { return new(MacDialog) }

////////////

type Button interface {
	Render()
}

type WinButton struct{}

func (b *WinButton) Render() { fmt.Println("render win button") }

type MacButton struct{}

func (b *MacButton) Render() { fmt.Println("render mac button") }

////////////

type Dialog interface {
	Render()
}

type WinDialog struct{}

func (b *WinDialog) Render() { fmt.Println("render win dialog") }

type MacDialog struct{}

func (b *MacDialog) Render() { fmt.Println("render mac dialog") }

////////////

type Application struct {
	factory GUIFactory
}

func NewApplication(platfrom string) *Application {
	var factory GUIFactory
	switch platfrom {
	case "win":
		factory = new(WinFactory)
	case "mac":
		factory = new(MacFactory)
	default:
		panic("invalid")
	}
	return &Application{
		factory: factory,
	}
}

func (app *Application) Render() {
	b := app.factory.NewButton()
	b.Render()

	d := app.factory.NewDialog()
	d.Render()
}

func main() {
	NewApplication("win").Render()
	NewApplication("mac").Render()
}
